import { defineComponent, computed, ref, watch, reactive, watchEffect, onMounted, onBeforeUnmount, provide, createVNode } from 'vue';
import Head from './Head.js';
import Body from './Body.js';
import { initColumns, initData, observerSizeChange, sortHandler, showHideChildren, addRemoveExpand, onResizeStart, onResizeMove, onResizeEnd, updateScrollFixed } from './utils.js';
import Spin from '../Spin/index.js';
import Summary from './Summary.js';

// 表格存储

const TableContextKey = Symbol('TableContextKey');
const index = /* @__PURE__ */ defineComponent({
  name: 'Table',
  props: {
    columns: {
      type: Array
    },
    data: {
      type: Array
    },
    rowKey: {
      type: String,
      default: 'id'
    },
    height: {
      type: Number,
      default: undefined
    },
    border: {
      type: Boolean,
      default: false
    },
    stripe: {
      type: Boolean,
      default: false
    },
    highlight: {
      type: Boolean
    },
    showHeader: {
      type: Boolean,
      default: true
    },
    selectedRowKeys: {
      type: Array,
      default: () => []
    },
    size: {
      type: String
    },
    spanMethod: {
      type: Function
    },
    showSummary: {
      type: Boolean
    },
    summaryMethod: {
      type: Function
    },
    loading: {
      type: Boolean
    },
    loadingText: {
      type: [String, Object]
    },
    title: {
      type: [String, Object]
    },
    footer: {
      type: [String, Object]
    },
    empty: {
      type: [String, Object]
    },
    virtual: {
      type: Boolean
    }
  },
  emits: ['rowSelect', 'rowChecked', 'checkedAll', 'sort', 'update:selectedRowKeys'],
  setup(props, {
    attrs,
    emit,
    expose
  }) {
    const classList = computed(() => ({
      'cm-table-wrap': true,
      'cm-table-border': props.border,
      'cm-table-stripe': props.stripe,
      'cm-table-small': props.size === 'small',
      'cm-table-with-title': props.title,
      'cm-table-with-footer': props.footer,
      'cm-table-with-summary': props.showSummary,
      'cm-table-resizing': store.resizing
    }));
    const {
      maxFixedLeft,
      minFixedRight
    } = initColumns(props.columns);
    const selectedRowKeys = ref(props.selectedRowKeys ?? []);
    let data = initData(props.data, props.rowKey);
    const wrap = ref();
    watch(() => props.selectedRowKeys, () => {
      selectedRowKeys.value = props.selectedRowKeys;
    });
    const store = reactive({
      columns: [],
      columnsRows: [],
      data: [],
      showFixedLeft: false,
      showFixedRight: true,
      checkedAll: false,
      resizing: false,
      x: 0,
      posX: 0,
      startX: 0,
      resizeId: undefined,
      headerSize: {
        with: 0,
        height: 48
      },
      summarySize: {
        with: 0,
        height: 0
      },
      headerLeft: 0
    });

    // 传入的data变化
    watchEffect(() => {
      data = initData(props.data, props.rowKey);
      store.data = data;
      store.checkedAll = false;
    });

    // 传入的columns变化
    watchEffect(() => {
      const {
        columnsRows,
        calcColumns
      } = initColumns(props.columns);
      store.columns = calcColumns;
      store.columnsRows = columnsRows;
      store.showFixedLeft = false;
      store.showFixedRight = true;
    });

    // 行选高亮事件
    const onSelectRow = row => {
      const lastRow = store.data.find(item => {
        return item._highlight;
      });
      if (lastRow) {
        lastRow._highlight = false;
      }
      store.data.forEach(item => {
        if (item.id === row.id) {
          item._highlight = true;
        }
      });
      emit('rowSelect', row, lastRow);
    };

    // 选择框选择，并计算是否所有都选中，排除禁用行
    const onRowChecked = (row, checked) => {
      store.data.forEach(item => {
        if (item.id === row.id) {
          item._checked = checked;
        }
      });
      let status = false;
      let checkedNum = 0;
      let total = 0;
      const checkedKeys = [];
      store.data.forEach(item => {
        if (!item._disabled) {
          total++;
        }
        if (item._checked) {
          checkedKeys.push(item.id);
          checkedNum++;
          status = 'indeterminate';
        }
      });
      if (checkedNum >= total) {
        status = true;
      }
      if (checkedKeys.join(',') !== selectedRowKeys.value?.join(',')) {
        selectedRowKeys.value = checkedKeys;
        emit('update:selectedRowKeys', checkedKeys);
      }
      store.checkedAll = status;
      emit('rowChecked', row, checked);
    };
    watch(() => selectedRowKeys.value, rowKeys => {
      if (rowKeys && rowKeys.length > 0) {
        store.data.forEach(item => {
          if (rowKeys.includes(item.id) && !item._checked) {
            item._checked = true;
          }
        });
      } else {
        store.data.filter(item => item._checked).forEach(item => {
          item._checked = false;
        });
      }
      let status = false;
      let checkedNum = 0;
      let total = 0;
      store.data.forEach(item => {
        if (!item._disabled) {
          total++;
        }
        if (item._checked) {
          checkedNum++;
          status = 'indeterminate';
        }
      });
      if (checkedNum >= total) {
        status = true;
      }
      store.checkedAll = status;
    }, {
      immediate: true
    });

    // 头部选择框选中事件,禁用的选择框不进行响应
    const onHeadChecked = checked => {
      store.checkedAll = checked;
      store.data.forEach(item => {
        if (checked && !item._disabled && !item._checked) {
          item._checked = checked;
        }
        if (!checked && !item._disabled && item._checked) {
          item._checked = checked;
        }
      });
      const checkedKeys = [];
      const rows = store.data.filter(item => {
        if (item._checked) {
          checkedKeys.push(item.id);
        }
        return item._checked;
      });
      if (checkedKeys.join(',') !== selectedRowKeys.value?.join(',')) {
        selectedRowKeys.value = checkedKeys;
        emit('update:selectedRowKeys', checkedKeys);
      }
      emit('checkedAll', rows);
    };

    // 点击排序执行
    const onSort = (column, sortType) => {
      sortHandler(store, column, sortType);
      if (props.onSort) {
        props.onSort(column, column.sortType);
      }
    };

    // 树形展开收缩
    const onShowChildren = row => {
      showHideChildren(store, row);
    };

    // 展开自定义内容
    const onExpand = (column, row) => {
      addRemoveExpand(store, column, row);
    };

    // resize开始
    const onDragStart = (column, e) => {
      onResizeStart(store, column, e);
      document.addEventListener('mousemove', onDragMove, false);
      document.addEventListener('mouseup', onDragEnd, false);
    };
    // resize鼠标移动
    const onDragMove = e => {
      onResizeMove(store, e);
    };
    // resize停止
    const onDragEnd = () => {
      document.removeEventListener('mousemove', onDragMove);
      document.removeEventListener('mouseup', onDragEnd);
      onResizeEnd(store, wrap.value);
    };

    // resize 辅助线条样式
    const resizeStyle = computed(() => ({
      'display': store.resizing ? 'block' : 'none',
      'left': store.posX + 'px'
    }));
    const getAllChecked = () => {
      return store.data.filter(item => {
        return item._checked;
      });
    };
    const setChecked = (id, checked) => {
      const row = store.data.find(item => {
        item.id === id;
      });
      onRowChecked(row, checked);
    };
    const onInitColumnWidth = (index, width) => {
      store.columns[index]._width = width;
    };
    const onResizeHeader = (width, height) => {
      store.headerSize.width = width;
      store.headerSize.height = height;
    };
    const onResizeSummary = (width, height) => {
      store.summarySize.width = width;
      store.summarySize.height = height;
    };
    const onScrollBody = (scrollLeft, clientWidth, scrollWidth) => {
      updateScrollFixed(maxFixedLeft, minFixedRight, store, scrollLeft, clientWidth, scrollWidth);
      if (store.headerLeft !== scrollLeft) {
        store.headerLeft = scrollLeft;
      }
    };
    expose({
      clearSelect() {
        store.data.filter(item => item._highlight).forEach(item => item._highlight = false);
      },
      checkAll(checked) {
        onHeadChecked(checked);
      },
      getAllChecked() {
        return getAllChecked();
      },
      setChecked
    });
    onMounted(() => {
      const body = wrap.value.querySelector('.cm-table-body');
      const ro = new ResizeObserver(entries => {
        entries.forEach(entry => {
          observerSizeChange(store, wrap.value);
        });
      });
      ro.observe(body);
      onBeforeUnmount(() => {
        ro.unobserve(body);
      });
    });
    const style = computed(() => {
      return {
        'max-height': props.height ? `${props.height}px` : ''
      };
    });
    const isSticky = computed(() => !!props.height);
    provide(TableContextKey, {
      store,
      onSelectRow,
      onRowChecked,
      onHeadChecked,
      onSort,
      onShowChildren,
      onExpand,
      onDragStart,
      highlight: props.highlight,
      border: props.border,
      spanMethod: props.spanMethod,
      empty: props.empty
    });
    return () => createVNode("div", {
      "class": classList.value,
      "ref": wrap
    }, [createVNode("div", {
      "class": "cm-table-resize-helper",
      "style": resizeStyle.value
    }, null), createVNode("div", {
      "class": "cm-table-loading"
    }, null), props.loading ? createVNode(Spin, {
      "type": "dot",
      "title": props.loadingText || ''
    }, null) : null, props.title ? createVNode("div", {
      "class": "cm-table-title"
    }, [props.title]) : null, createVNode("div", {
      "class": "cm-table",
      "style": style.value
    }, [props.showHeader ? createVNode(Head, {
      "data": store,
      "sticky": isSticky.value,
      "onInitColumnWidth": onInitColumnWidth,
      "onResizeHeader": onResizeHeader,
      "virtual": props.virtual
    }, null) : null, createVNode(Body, {
      "data": store,
      "onScroll": onScrollBody,
      "height": props.height,
      "virtual": props.virtual
    }, null), props.showSummary ? createVNode(Summary, {
      "data": store,
      "onResizeSummary": onResizeSummary,
      "summaryMethod": props.summaryMethod
    }, null) : null]), props.footer ? createVNode("div", {
      "class": "cm-table-footer"
    }, [props.footer]) : null]);
  }
});

export { TableContextKey, index as default };
